/*
 * Copyright (c) 2019. Mikes. All rights reserved.
 *
 * You can contact me with sending email to bWlrZXNfMjAxMkAxNjMuY29t for more information!
 */

package com.climber.android.commonres.app.service

import com.climber.android.commonres.UploadFile
import com.climber.android.commonsdk.app.AppConstants
import com.climber.android.commonsdk.api.APIError
import com.climber.android.commonsdk.api.AccountToken
import com.climber.android.commonsdk.api.entity.APIResponse
import com.climber.android.commonsdk.api.entity.APIResponseData
import com.climber.android.commonsdk.api.entity.TokenAPIResponseData
import io.ganguo.library.mvp.BaseContext
import io.ganguo.library.mvp.util.CBaseUtils
import io.ganguo.library.mvp.util.GsonUtils
import io.reactivex.Observable
import io.reactivex.ObservableSource
import io.reactivex.functions.Function
import okhttp3.MultipartBody
import okhttp3.RequestBody
import retrofit2.http.Body
import retrofit2.http.Header
import retrofit2.http.Headers
import retrofit2.http.POST

/**
 * Created by Mikes at 2019-11-04 15:33
 */
class DynamicStringResponseTransfer<R>(private val cls : Class<R>):
        Function<String, ObservableSource<R>>{
    override fun apply(stringResponse: String): ObservableSource<R> {
        val rawResponse = GsonUtils.fromJson<APIResponse>(stringResponse, APIResponse::class.java)

        return if(rawResponse?.isSuccessful() == true){
            val apiResponse = GsonUtils.fromJson(stringResponse, cls)
            Observable.just(apiResponse)
        } else{
            Observable.error(APIError.ServerError(errorCode = rawResponse.getServerErrorCode(), errorMsg = rawResponse.getServerErrorMsg()))
        }
    }
}

class TokenResponseTransfer:
        Function<String, ObservableSource<TokenAPIResponseData>>{
    override fun apply(stringResponse: String): ObservableSource<TokenAPIResponseData> {
        val tokenResponse = GsonUtils.fromJson<TokenAPIResponseData>(stringResponse, TokenAPIResponseData::class.java)
        return if(tokenResponse?.isSuccessful() == true){
            AccountToken.loginToken = tokenResponse.data
            Observable.just(tokenResponse)
        } else{
            Observable.error(APIError.ServerError(errorCode = tokenResponse.getServerErrorCode(), errorMsg = tokenResponse.getServerErrorMsg()))
        }
    }
}

enum class AppPayType{
    Wallet,
    AliPay,
    WeChat;

    fun apiParam() : String = when(this){
        Wallet -> "0"
        AliPay -> "1"
        WeChat -> "2"
    }
}

/**
 * 获取手机验证码的类型
 */
enum class OTPRequestType{
    BindNewPhone,               // 修改手机号后绑定的新手机号
    ModifyPhone,                // 修改手机号
    ModifyPassword,             // 修改密码
    FindPassword,               // 找回密码
    RegisterPhone;              // 社交注册时绑定手机号

    fun generateOTPRequestInfo(countryCode: String, phoneNumber: String) : OTPRequestInfo{
        return when(this){
            ModifyPhone -> {
                OTPRequestInfo.ModifyPhone(countryCode = countryCode, number = phoneNumber)
            }
            ModifyPassword -> {
                OTPRequestInfo.ModifyPassword(countryCode = countryCode, number = phoneNumber)
            }
            BindNewPhone -> {
                OTPRequestInfo.BindNewPhone(countryCode = countryCode, number = phoneNumber)
            }
            FindPassword ->{
                OTPRequestInfo.FindPassword(countryCode = countryCode, number = phoneNumber)
            }
            RegisterPhone ->{
                OTPRequestInfo.Register(countryCode = countryCode, number = phoneNumber)
            }
        }
    }
}

sealed class OTPRequestInfo {
    abstract fun apiParameters(): Map<String, String>

    // 注册
    data class Register(val countryCode: String, val number: String) : OTPRequestInfo() {
        override fun apiParameters(): Map<String, String> = mapOf(
                Pair("type", "1"),
                Pair("mobile", countryCode + number)
        )
    }

    // 找回密码
    data class FindPassword(val countryCode: String, val number: String) : OTPRequestInfo() {
        override fun apiParameters(): Map<String, String> = mapOf(
                Pair("type", "2"),
                Pair("mobile", countryCode + number)
        )
    }

    // 修改密码
    data class ModifyPassword(val countryCode: String, val number: String) : OTPRequestInfo() {
        override fun apiParameters(): Map<String, String> = mapOf(
                Pair("type", "3"),
                Pair("mobile", countryCode + number)
        )
    }

    // 修改手机号
    data class ModifyPhone(val countryCode: String, val number: String) : OTPRequestInfo() {
        override fun apiParameters(): Map<String, String> = mapOf(
                Pair("type", "4"),
                Pair("mobile", countryCode + number)
        )
    }

    // 绑定新手机号
    data class BindNewPhone(val countryCode: String, val number: String) : OTPRequestInfo() {
        override fun apiParameters(): Map<String, String> = mapOf(
                Pair("type", "5"),
                Pair("mobile", countryCode + number)
        )
    }
}

interface CoreService {

    companion object{
        val coreServiceAPI : CoreService by lazy(LazyThreadSafetyMode.SYNCHRONIZED){
            CBaseUtils.obtainAppComponentFromContext(BaseContext.getInstance())
                .repositoryManager()
                .obtainRetrofitService(CoreService::class.java)
        }
    }

    @Headers("Domain-Name: ${AppConstants.API_BASE_URL}")
    @POST("single/up")
    fun issueUploadSingleFile(@Body file: MultipartBody, @Header("custom-ContentType") contentType: String?=null):
            Observable<APIResponseData<UploadFile>>

    /**
     * 发送验证码
     * body {@link OTPRequestInfo}
     *
     * type : 1，注册；2， 找回密码；3，修改密码；4，修改手机号；5，修改手机号后绑定的新手机号
     */
    @Headers("Domain-Name: ${AppConstants.API_BASE_URL}")
    @POST("send/sms")
    fun issueSendOTP(@Body body: RequestBody): Observable<APIResponse>

    /**
     * 验证手机号与验证码
     */
    @Headers("Domain-Name: ${AppConstants.API_BASE_URL}")
    @POST("verify/code")
    fun issueVerifyOTPCode(@Body body: RequestBody): Observable<APIResponse>
}